package com.joinval.common.utils;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Enumeration;
import java.util.TooManyListenersException;

import gnu.io.CommPortIdentifier;
import gnu.io.NoSuchPortException;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.SerialPortEvent;
import gnu.io.SerialPortEventListener;
import gnu.io.UnsupportedCommOperationException;
/**
 * @Author zhizuntop
 * @create 2023/9/11 09:59
 * Java 串口通信需要使用 JavaComm API。JavaComm API 是一套 Java 串口通信 API，是由 Sun 公司提供的，目前已被 Oracle 公司继续维护。使用 JavaComm API 可以在 Java 程序中实现串口通信。
 * JavaComm API 提供了两个主要的类：CommPortIdentifier 和 SerialPort。
 * CommPortIdentifier 类用于获取串口端口的标识符，可以通过它来获取已经打开的串口对象。
 * SerialPort 类则是串口通信的核心，提供了一系列方法用于读写串口数据、设置串口参数等。
 * Java 串口通信协议一般分为两种：ASCII 协议和二进制协议。ASCII 协议是指将数据按照 ASCII 码进行传输，比较容易实现，但是数据量较大，传输速度较慢；二进制协议则是指将数据按照二进制格式进行传输，数据量较小，传输速度较快，但是实现较为困难。
 * 在实现 Java 串口通信时，需要根据实际情况选择合适的协议，并根据协议编写相应的数据读写代码。同时，还需要注意串口参数的设置，例如波特率、数据位、停止位、校验位等，以保证数据能够正确地传输。
 *
 */

public class SerialCommunication implements SerialPortEventListener {

    private SerialPort serialPort;
    private InputStream inputStream;
    private OutputStream outputStream;

    public void initialize(String portName) {
        try {
            // 获取串口标识符
            CommPortIdentifier portId = CommPortIdentifier.getPortIdentifier(portName);

            // 打开串口
            serialPort = (SerialPort) portId.open("SerialCommunication", 2000);

            // 设置串口参数(波特率, 数据位, 停止位, 校验位)
            serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);

            // 获取输入输出流
            inputStream = serialPort.getInputStream();
            outputStream = serialPort.getOutputStream();

            // 添加串口监听器
            serialPort.addEventListener(this);
            serialPort.notifyOnDataAvailable(true);
        } catch (NoSuchPortException | PortInUseException | UnsupportedCommOperationException | IOException | TooManyListenersException e) {
            e.printStackTrace();
        }
    }

    public void sendData(String data) {
        try {
            // 发送数据
            outputStream.write(data.getBytes());
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public synchronized void close() {
        if (serialPort != null) {
            serialPort.removeEventListener();
            serialPort.close();
        }
    }

    @Override
    public synchronized void serialEvent(SerialPortEvent event) {
        if (event.getEventType() == SerialPortEvent.DATA_AVAILABLE) {
            try {
                // 读取数据
                byte[] buffer = new byte[1024];
                int len = -1;                while ((len = inputStream.read(buffer)) > -1) {
                    String receivedData = new String(buffer, 0, len);
                    System.out.print(receivedData);
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        SerialCommunication serialCommunication = new SerialCommunication();

        // 获取可用的串口列表
        Enumeration<CommPortIdentifier> portEnum = CommPortIdentifier.getPortIdentifiers();
        while (portEnum.hasMoreElements()) {
            CommPortIdentifier portIdentifier = portEnum.nextElement();
            System.out.println(portIdentifier.getName());
        }

        // 初始化串口
        serialCommunication.initialize("COM3");

        // 发送数据
        serialCommunication.sendData("Hello, World!");

        // 关闭串口
        serialCommunication.close();
    }

}
